import axios from 'axios'
import type { AxiosInstance } from 'axios'
import router from "@/router"
import qs from 'qs'
import requestConfig from '@/utils/config'
import type { HttpRequestConfig } from '@/utils/config'

class Http {

    // axios 实例
    private instance: AxiosInstance
    // config
    private config: HttpRequestConfig

    constructor(config: HttpRequestConfig) {

        this.config = config

        const { needAuth, tokenAlias = 'authToken', ...cf } = config

        this.instance = axios.create(cf)

        this.instance.interceptors.request.use(config =>
            {
                // 如果需要携带 token
                // TODO token 命名待定
                if (needAuth) {
                    let token = localStorage.getItem(tokenAlias)
                    if (token) {
                        let tmp = {}
                        // @ts-ignore
                        tmp[tokenAlias] = token
                        config.headers && (Object.assign(config.headers, tmp))
                    } else {
                        // TODO 跳转统一页面
                        // throw new Error('Token is required!')
                    }
                }
                return config
            }, error => {
                return Promise.reject(error)
            }
        )

        this.instance.interceptors.response.use(response => {
            const { status: respStatus, data: respData } = response
            if (respStatus === 200) {
                // TODO 服务自定义的状态码判断，或在后续中判断
                let { code, data, ...other } = respData
                if (code === 10000 || code === '10000') {
                    if (data) {
                        // if (other) Object.assign(data, other)
                        return Promise.resolve(data)
                    }
                    return Promise.resolve(respData)
                } else {
                    ElMessage.error(respData.msg || respData.message || '系统异常，请联系管理员！')
                    return Promise.reject(respData.data || respData)
                }
            } else {
                return Promise.reject(response)
            }
        }, error => {
            let status = error.response.status
            switch (status) {
                case 401:
                    ElMessage.error('资源禁止访问！')
                    router.replace({
                        path: '/login'
                    }).then(() => {
                        localStorage.clear()
                        sessionStorage.clear()
                    })
                    break
                case 403:
                    ElMessage.error('资源未授权！')
                    break
                case 404:
                    ElMessage.error('资源未找到！')
                    break
                case 500:
                    ElMessage.error('系统异常！')
                    break
                case 503:
                    ElMessage.error('服务不可用！')
                    break
                // TODO any others
                default:
                    break
            }
            return Promise.reject(error)
        })
    }

    get<T> (url: string, params?: object | any): Promise<T> {
        return new Promise((resolve, reject) => {
            this.instance.get<any, T>(url, { params }).then(res => resolve(res)).catch(err => reject(err));
        })
    }

    postJson<T> (url: string, params: object | any): Promise<T> {
        return new Promise((resolve, reject) => {
            this.instance.post<any, T>(url, params, {
                headers: {
                    'Content-Type': 'application/json'
                }
            }).then(res => resolve(res)).catch(err => reject(err))
        })
    }

    postForm<T> (url: string, params: object | any): Promise<T> {
        return new Promise((resolve, reject) => {
            this.instance.post<any, T>(url, qs.stringify(params), {
                headers: {
                    'Content-Type': 'application/x-www-form-urlencoded'
                }
            }).then(res => resolve(res)).catch(err => reject(err))
        })
    }

    put<T> (url: string, params: object | any): Promise<T> {
        return new Promise((resolve, reject) => {
            this.instance.put<any, T>(url, params).then(res => resolve(res)).catch(err => reject(err))
        })
    }

    delete<T> (url: string, params?: object | any): Promise<T> {
        return new Promise((resolve, reject) => {
            this.instance.delete<any, T>(url, { params }).then(res => resolve(res)).catch(err => reject(err))
        })
    }
}

export { Http }

const http = new Http(requestConfig)

export default http


